﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Yxinmt.Interface;
using Yxinmt.Utility;

namespace Yxinmt.Controls
{
    public class InkCanvas : BaseControl, IControl
    {
        private System.Windows.Controls.InkCanvas _InkCanvas { get; set; }
        bool _IsMouseEnter { get; set; }
        bool _IsKeyUp { get; set; }

        public InkCanvas(Dictionary<string, object> property, IComponent component)
        {
            Property = property;
            _Component = component;

            _InkCanvas = new System.Windows.Controls.InkCanvas();
            this.Element = _InkCanvas;

            InitSet();
            this.SetProperty();
            this.SetControlProperty(false, false);

            _TextFontSize = 16;
            _TextFontFamily = "宋体";

            _ChildElementList = new ConcurrentDictionary<Guid, ConcurrentStack<object>>();
            _BackChildElementList = new ConcurrentDictionary<Guid, ConcurrentStack<object>>();

            //if (_Window.IsReceiver) _InkCanvas.EditingMode = System.Windows.Controls.InkCanvasEditingMode.None;

            AddControl<InkCanvas>(_InkCanvasList);

            //_UserId = Cache.StateData.MeetingInfo.UserId;
        }

        Guid _UserId { get; set; }

        public override void Add(System.Windows.FrameworkElement control)
        {
            AddChild(control, _UserId);
        }

        public void AddChild(System.Windows.FrameworkElement control, Guid userId)
        {
            _InkCanvas.Children.Add(control);
            AddChildElement(control, userId);

            IsSave = false;
        }

        void AddChildElement(object obj, Guid userId)
        {
            if (!_ChildElementList.ContainsKey(userId))
            {
                _ChildElementList[userId] = new ConcurrentStack<object>();
                _BackChildElementList[userId] = new ConcurrentStack<object>();
            }

            _ChildElementList[userId].Push(obj);
        }

        public override void Clear()
        {
            Clear(_UserId);

            //_DataAction.InvokeAsync(GetEntity2(), (int)DataDistribution.ActionTypes.InkCanvas.Clear);
        }

        public void Clear(Guid userId)
        {
            if (userId != Guid.Empty && _ChildElementList.Keys.Where(w => w != userId).Count() > 0)
            {
                if (!_ChildElementList.ContainsKey(userId)) return;

                var list = _ChildElementList[userId].Reverse().ToList();

                foreach (var ele in list)
                {
                    if (ele is System.Windows.Ink.Stroke && _InkCanvas.Strokes.Contains((System.Windows.Ink.Stroke)ele))
                    {
                        _InkCanvas.Strokes.Remove((System.Windows.Ink.Stroke)ele);
                    }
                    else if (ele is System.Windows.UIElement && _InkCanvas.Children.Contains((System.Windows.UIElement)ele))
                    {
                        _InkCanvas.Children.Remove((System.Windows.UIElement)ele);
                    }
                }

                _ChildElementList[userId] = new ConcurrentStack<object>();
                _BackChildElementList[userId] = new ConcurrentStack<object>();

                if (_InkCanvas.Strokes.Count > 0 || _InkCanvas.Children.Count > 0)
                {
                    var list2 = _InkCanvas.Strokes.Except((from a in _ChildElementList
                                                           from b in a.Value
                                                           where b is System.Windows.Ink.Stroke
                                                           select b as System.Windows.Ink.Stroke));

                    foreach (var d in list2) _InkCanvas.Strokes.Remove(d);
                }
            }
           else
            {
                if (_InkCanvas.Children.Count > 0) _InkCanvas.Children.Clear();
                if (_InkCanvas.Strokes.Count > 0) _InkCanvas.Strokes.Clear();
                _ChildElementList = new ConcurrentDictionary<Guid, ConcurrentStack<object>>();
                _BackChildElementList = new ConcurrentDictionary<Guid, ConcurrentStack<object>>();
                if (_BackImage != null) _InkCanvas.Children.Add(_BackImage);
            }
            IsSave = false;
        }

        public void ClearStrokes()
        {
            if (_InkCanvas.Strokes.Count > 0) _InkCanvas.Strokes.Clear();
            _ChildElementList = new ConcurrentDictionary<Guid, ConcurrentStack<object>>();
            _BackChildElementList = new ConcurrentDictionary<Guid, ConcurrentStack<object>>();
            IsSave = false;
        }

        public bool IsDraw
        {
            get { return _ChildElementList.Count > 0; }
        }

        public bool IsSave { get; set; }

        ConcurrentDictionary<Guid, ConcurrentStack<object>> _ChildElementList { get; set; }
        ConcurrentDictionary<Guid, ConcurrentStack<object>> _BackChildElementList { get; set; }

        public void Cancel()
        {
            Cancel(_UserId);

            //_DataAction.InvokeAsync(GetEntity2(), (int)DataDistribution.ActionTypes.InkCanvas.Cancel);
        }

        public void BackCancel()
        {
            BackCancel(_UserId);

            //_DataAction.InvokeAsync(GetEntity2(), (int)DataDistribution.ActionTypes.InkCanvas.BackCancel);
        }

        public void Cancel(Guid userId)
        {
            if (userId == Guid.Empty) userId = _UserId;

            if (_ChildElementList.Count > 0 && _ChildElementList.ContainsKey(userId))
            {
                object obj = null;
                _ChildElementList[userId].TryPop(out obj);
                if (obj != null) _BackChildElementList[userId].Push(obj);
                if (obj is System.Windows.Ink.Stroke && _InkCanvas.Strokes.Contains((System.Windows.Ink.Stroke)obj))
                {
                    _InkCanvas.Strokes.Remove((System.Windows.Ink.Stroke)obj);
                }
                else if (obj is System.Windows.UIElement && _InkCanvas.Children.Contains((System.Windows.UIElement)obj))
                {
                    _InkCanvas.Children.Remove((System.Windows.UIElement)obj);
                }
                IsSave = false;
            }
        }

        public void BackCancel(Guid userId)
        {
            if (userId == Guid.Empty) userId = _UserId;

            if (_BackChildElementList.Count > 0 && _BackChildElementList.ContainsKey(userId))
            {
                object obj = null;
                _BackChildElementList[userId].TryPop(out obj);
                if (obj != null) _ChildElementList[userId].Push(obj);
                if (obj is System.Windows.Ink.Stroke)
                {
                    _InkCanvas.Strokes.Add((System.Windows.Ink.Stroke)obj);
                }
                else if (obj is System.Windows.UIElement)
                {
                    _InkCanvas.Children.Add((System.Windows.UIElement)obj);
                }
                IsSave = false;
            }
        }

        bool _IsBackKey { get; set; }

        private void SetProperty()
        {
            _IsMouseEnter = Property.GetValue<bool>("IsMouseEnter");
            _IsKeyUp = Property.GetValue<bool>("IsKeyUp");
            _IsBackKey = Property.GetValue<bool>("IsBackKey");

            _InkCanvas.ForceCursor = true;
            SetDefaultValue("Cursor", "Pen");
        }

        protected override void SetProperty(string name, object value)
        {
            System.Windows.Controls.InkCanvas c = _InkCanvas;
            switch (name)
            {
                case "Name": c.Name = string.Concat("ink_", (string)value); break;
                case "Height": c.Height = Convert.ToDouble(value); break;
                case "Width": c.Width = Convert.ToDouble(value); break;
                case "Dock": System.Windows.Controls.DockPanel.SetDock(c, this.GetDock((string)value)); break;
                case "BackColor": c.Background = GetColor((string)value); break;
                case "ControlAlign": SetControlAlign((string)value); break;
                case "Visible": SetVisible((bool)value); break;
                case "GridRowColumn": SetGridRowColumn((string)value); break;
                case "BackImageUrl": SetBackgroundImage((string)value); break;
                case "ZIndex": SetZIndex((int)value); break;
                case "Cursor": c.Cursor = GetCursor((string)value); break;
                case "DefaultColor": SetColor((string)value); break;
                case "DefaultWidth": SetStrokeWidth(Convert.ToDouble(value)); break;
            }
        }

        public override object GetValue()
        {
            if (_InkCanvas.Strokes.Count == 0) return null;

            return GetStrokesData(_InkCanvas.Strokes);
        }

        byte[] GetStrokesData(System.Windows.Ink.StrokeCollection strokes)
        {
            using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
            {
                strokes.Save(ms, true);
                return ms.ToArray();
            }
        }

        public override void SetValue(object value)
        {
            if (value is byte[]) _InkCanvas.Strokes = new System.Windows.Ink.StrokeCollection(new MemoryStream((byte[])value));
        }

        public void SetStrokeWidth(double width)
        {
            if (width > 0)
            {
                _InkCanvas.DefaultDrawingAttributes.Width = width;
                _InkCanvas.DefaultDrawingAttributes.Height = width;
            }
        }

        bool _IsFill { get; set; }

        public void SetFill(bool blFill)
        {
            _IsFill = blFill;
        }

        public override void EventLoad()
        {
            if (_IsMouseEnter)
            {
                _InkCanvas.MouseEnter += _InkCanvas_MouseEnter;
            }
            if (_IsKeyUp) _InkCanvas.KeyUp += _InkCanvas_KeyUp;

            _InkCanvas.PreviewMouseLeftButtonDown += _InkCanvas_PreviewMouseLeftButtonDown;

            _InkCanvas.MouseMove += _InkCanvas_MouseMove;

            _InkCanvas.MouseUp += _InkCanvas_MouseUp;

            _InkCanvas.TouchUp += _InkCanvas_TouchUp;
        }

        private void _InkCanvas_TouchUp(object sender, System.Windows.Input.TouchEventArgs e)
        {
            //if (DataDistribution.Distribution.IsReceiver && !DataDistribution.Distribution.IsSyncNote) { e.Handled = true; return; }

            if (!_IsTouchUp)
            {
                _IsMouseUp = true;
                MouseUp();
            }
        }

        bool _IsTouchUp { get; set; }
        bool _IsMouseUp { get; set; }

        void _InkCanvas_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            //if (DataDistribution.Distribution.IsReceiver && !DataDistribution.Distribution.IsSyncNote) { e.Handled = true; return; }

            _IsTouchUp = true;
            if (!_IsMouseUp) MouseUp();

            _IsMouseUp = false;
        }

        void MouseUp()
        {
            try
            {
                _IsMouseDown = false;

                object ele = null;

                if (ShapeType == InkCanvasShapeType.Circle && _Circle != null) ele = _Circle;
                else if (ShapeType == InkCanvasShapeType.Ellipse && _Ellipse != null) ele = _Ellipse;
                else if (ShapeType == InkCanvasShapeType.Line && _Line != null) ele = _Line;
                else if (ShapeType == InkCanvasShapeType.Rect && _Rectangle != null) ele = _Rectangle;

                _Line = null;
                _Rectangle = null;
                _Ellipse = null;
                _Circle = null;

                if (ShapeType == InkCanvasShapeType.Ink && _InkCanvas.Strokes.Count > 0)
                {
                    IsSave = false;
                    ele = _InkCanvas.Strokes.Last();

                    Task.Run(() =>
                    {
                        try
                        {
                            AddChildElement(ele, _UserId);
                        }
                        catch
                        {
                        }
                    });
                }

                if (ShapeType != InkCanvasShapeType.Text) _InkCanvas.Focus();

                //if (ele != null) _DataAction.InvokeAsync(GetEntity(GetInkElement(ele)), (int)DataDistribution.ActionTypes.InkCanvas.Draw);
            }
            catch (Exception ex)
            {
                LoggerProxy.Exception(Name, "MouseUp", ex);
            }
        }

        System.Windows.Shapes.Line _Line { get; set; }
        System.Windows.Shapes.Rectangle _Rectangle { get; set; }
        System.Windows.Shapes.Ellipse _Ellipse { get; set; }
        System.Windows.Shapes.Ellipse _Circle { get; set; }
        System.Windows.Controls.TextBox _TextBox { get; set; }

        InkCanvasShapeType _ShapeType { get; set; }
        public InkCanvasShapeType ShapeType
        {
            get { return _ShapeType; }
            set
            {
                _ShapeType = value;
                if (value == InkCanvasShapeType.Ink) _InkCanvas.EditingMode = System.Windows.Controls.InkCanvasEditingMode.Ink;
                else _InkCanvas.EditingMode = System.Windows.Controls.InkCanvasEditingMode.None;
            }
        }

        private void Draw(bool blInit)
        {
            switch (ShapeType)
            {
                case InkCanvasShapeType.Line: DrawLine(blInit); break;
                case InkCanvasShapeType.Rect: DrawRect(blInit); break;
                case InkCanvasShapeType.Ellipse: DrawEllipse(blInit); break;
                case InkCanvasShapeType.Circle: DrawCircle(blInit); break;
                case InkCanvasShapeType.Text: DrawTextBox(blInit); break;
            }

            IsSave = false;
        }

        double _TextFontSize { get; set; }
        string _TextFontFamily { get; set; }
        bool _TextBold { get; set; }
        bool _TextItalic { get; set; }

        System.Windows.Controls.Image _BackImage { get; set; }

        public void DrawBackImage(System.Windows.Media.ImageSource imageSource)
        {
            _BackImage = new System.Windows.Controls.Image();
            _BackImage.Source = imageSource;
            System.Windows.Controls.InkCanvas.SetLeft(_BackImage, 0);
            System.Windows.Controls.InkCanvas.SetTop(_BackImage, 0);
            _BackImage.Width = _InkCanvas.ActualWidth + 100;

            _InkCanvas.Children.Add(_BackImage);
        }

        public byte[] SaveToPng()
        {
            IsSave = true;

            return GetInkPng();
        }

        byte[] GetInkPng()
        {
            using (System.IO.MemoryStream ms = new MemoryStream())
            {
                System.Windows.Media.Imaging.BitmapEncoder encoder = new System.Windows.Media.Imaging.PngBitmapEncoder();
                System.Windows.Media.Imaging.RenderTargetBitmap bitmap = new System.Windows.Media.Imaging.RenderTargetBitmap(Convert.ToInt32(_InkCanvas.ActualWidth), Convert.ToInt32(_InkCanvas.ActualHeight), 0, 0, System.Windows.Media.PixelFormats.Default);
                bitmap.Render(_InkCanvas);

                encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(bitmap));
                encoder.Save(ms);

                return ms.ToArray();
            }
        }

        public byte[] SaveInkElements()
        {
            IsSave = true;
            if (_ChildElementList.Count == 0) return null;

            InkElement ele = null;
            List<InkElement> inkElementList = new List<InkElement>();

            foreach (var kvp in _ChildElementList)
            {
                foreach (var e in kvp.Value.Reverse())
                {
                    ele = GetInkElement(e);
                    if (ele != null) inkElementList.Add(ele);
                }
            }

            return System.Text.Encoding.UTF8.GetBytes(Utility.Common.ToJson(inkElementList));
        }

        public void SetInkElements(byte[] bytes)
        {
            if (bytes == null) return;
            string json = System.Text.Encoding.UTF8.GetString(bytes);
            List<InkElement> inkElementList = Utility.Common.JsonTo<List<InkElement>>(json);

            inkElementList.ForEach(ele => SetInkElement(ele, _UserId));

            IsSave = true;
        }

        InkElement GetInkElement(object ele)
        {
            if (ele is System.Windows.Ink.Stroke) return GetStrokeInkElement(ele as System.Windows.Ink.Stroke);
            else if (ele is System.Windows.Shapes.Line) return GetLinkInkElement(ele as System.Windows.Shapes.Line);
            else if (ele is System.Windows.Shapes.Rectangle) return GetRectInkElement(ele as System.Windows.Shapes.Rectangle);
            else if (ele is System.Windows.Shapes.Ellipse) return GetEllipseInkElement(ele as System.Windows.Shapes.Ellipse);
            else if (ele is System.Windows.Controls.TextBox) return GetTextBoxInkElement(ele as System.Windows.Controls.TextBox);

            return null;
        }

        void SetInkElement(InkElement ele, Guid userId)
        {
            switch (ele.ShapeType)
            {
                case InkCanvasShapeType.Circle:
                case InkCanvasShapeType.Ellipse: SetElllipseElement(ele, userId); break;
                case InkCanvasShapeType.Ink: SetStrokeElement(ele, userId); break;
                case InkCanvasShapeType.Line: SetLineElement(ele, userId); break;
                case InkCanvasShapeType.Rect: SetRectElement(ele, userId); break;
                case InkCanvasShapeType.Text: SetTextElement(ele, userId); break;
            }
        }

        InkElement GetStrokeInkElement(System.Windows.Ink.Stroke ele)
        {
            System.Windows.Ink.StrokeCollection strokes = new System.Windows.Ink.StrokeCollection();
            strokes.Add(ele);

            return new InkElement()
            {
                ShapeType = InkCanvasShapeType.Ink,
                Stroke = GetStrokesData(strokes)
            };
        }

        void SetStrokeElement(InkElement ele, Guid userId)
        {
            System.Windows.Ink.StrokeCollection strokes = new System.Windows.Ink.StrokeCollection(new MemoryStream(ele.Stroke));
            System.Windows.Ink.Stroke stroke = strokes.Count > 0 ? strokes[0] : null;
            if (stroke == null) return;

            IsSave = false;
            AddChildElement(stroke, userId);
            _InkCanvas.Strokes.Add(stroke);
        }

        public byte[] StrokesSaveToPng()
        {
            return _InkCanvas.Strokes.Count > 0 ? GetInkPng() : null;
        }

        private void DrawTextBox(bool blInit)
        {
            if (blInit)
            {
                _TextBox = new System.Windows.Controls.TextBox();
                System.Windows.Controls.InkCanvas.SetLeft(_TextBox, _MouseDownPoint.X);
                System.Windows.Controls.InkCanvas.SetTop(_TextBox, _MouseDownPoint.Y);

                _TextBox.FontSize = _TextFontSize;
                _TextBox.Foreground = new System.Windows.Media.SolidColorBrush(_InkCanvas.DefaultDrawingAttributes.Color);
                _TextBox.FontFamily = new System.Windows.Media.FontFamily(_TextFontFamily);
                _TextBox.BorderBrush = GetColor("Transparent");
                _TextBox.BorderThickness = new System.Windows.Thickness(0);
                _TextBox.Background = GetColor("Transparent");
                if (_TextItalic) _TextBox.FontStyle = System.Windows.FontStyles.Italic;
                if (_TextBold) _TextBox.FontWeight = System.Windows.FontWeights.Bold;

                Add(_TextBox);

                _TextBox.Focus();
                _TextBox.LostFocus += _TextBox_LostFocus;
            }
        }

        InkElement GetTextBoxInkElement(System.Windows.Controls.TextBox textBox)
        {
            InkElement ele = new InkElement();

            ele.ShapeType = InkCanvasShapeType.Text;
            ele.X = System.Windows.Controls.InkCanvas.GetLeft(textBox);
            ele.Y = System.Windows.Controls.InkCanvas.GetTop(textBox);
            ele.StrokeColor = ((System.Windows.Media.SolidColorBrush)textBox.Foreground).Color.ToString();
            ele.FontSize = textBox.FontSize;
            if (textBox.FontFamily.FamilyNames.Count > 0) ele.FontFamily = textBox.FontFamily.FamilyNames.First().Value;
            ele.Text = textBox.Text;
            ele.Bold = textBox.FontWeight == System.Windows.FontWeights.Bold;
            ele.Italic = textBox.FontStyle == System.Windows.FontStyles.Italic;

            return ele;
        }

        void SetTextElement(InkElement ele,  Guid userId)
        {
            var textBox = new System.Windows.Controls.TextBox();
            System.Windows.Controls.InkCanvas.SetLeft(textBox, ele.X);
            System.Windows.Controls.InkCanvas.SetTop(textBox, ele.Y);

            textBox.FontSize = ele.FontSize;
            textBox.Foreground = new System.Windows.Media.SolidColorBrush(Utility.Common.GetColor(ele.StrokeColor));
            textBox.FontFamily = new System.Windows.Media.FontFamily(ele.FontFamily);
            textBox.BorderBrush = GetColor("Transparent");
            textBox.BorderThickness = new System.Windows.Thickness(0);
            textBox.Background = GetColor("Transparent");
            if (ele.Italic) textBox.FontStyle = System.Windows.FontStyles.Italic;
            if (ele.Bold) textBox.FontWeight = System.Windows.FontWeights.Bold;
            textBox.Text = ele.Text;

            AddChild(textBox, userId);
        }

        void _TextBox_LostFocus(object sender, System.Windows.RoutedEventArgs e)
        {
            try
            {
                var textBox = (System.Windows.Controls.TextBox)sender;
                textBox.IsReadOnly = true;
                textBox.Cursor = GetCursor("Arrow");

                if (string.IsNullOrEmpty(textBox.Text.Trim()))
                {
                    _InkCanvas.Children.Remove(textBox);
                    Utility.Common.ConcurrentStackRemove<object>(_ChildElementList[_UserId], textBox);
                    IsSave = false;
                }
                else
                {
                   //_DataAction.InvokeAsync(GetEntity(GetTextBoxInkElement(textBox)), (int)DataDistribution.ActionTypes.InkCanvas.Draw);
                }
            }
            catch (Exception ex)
            {
                LoggerProxy.Exception(Name, "_TextBox_LostFocus", ex);
            }
        }

        private void DrawCircle(bool blInit)
        {
            if (blInit)
            {
                _Circle = new System.Windows.Shapes.Ellipse();
                _Circle.Stroke = new System.Windows.Media.SolidColorBrush(_InkCanvas.DefaultDrawingAttributes.Color);
                _Circle.StrokeThickness = _InkCanvas.DefaultDrawingAttributes.Width;
                System.Windows.Controls.InkCanvas.SetLeft(_Circle, _MouseDownPoint.X);
                System.Windows.Controls.InkCanvas.SetTop(_Circle, _MouseDownPoint.Y);
                if (_IsFill) _Circle.Fill = _Circle.Stroke;

                Add(_Circle);
            }
            else if (_Circle != null)
            {
                double x = (_MouseMousePoint.X + _MouseDownPoint.X) / 2;
                double y = (_MouseMousePoint.Y + _MouseDownPoint.Y) / 2;
                double r = 0;

                double w = Math.Abs(_MouseMousePoint.X - _MouseDownPoint.X);
                double h = Math.Abs(_MouseMousePoint.Y - _MouseDownPoint.Y);

                r = Math.Sqrt(w * w + h * h) / 2;

                System.Windows.Controls.InkCanvas.SetLeft(_Circle, x - r);
                System.Windows.Controls.InkCanvas.SetTop(_Circle, y - r);

                _Circle.Width = r * 2;
                _Circle.Height = r * 2;
            }
        }

        private void DrawEllipse(bool blInit)
        {
            if (blInit)
            {
                _Ellipse = new System.Windows.Shapes.Ellipse();
                _Ellipse.Stroke = new System.Windows.Media.SolidColorBrush(_InkCanvas.DefaultDrawingAttributes.Color);
                _Ellipse.StrokeThickness = _InkCanvas.DefaultDrawingAttributes.Width;
                System.Windows.Controls.InkCanvas.SetLeft(_Ellipse, _MouseDownPoint.X);
                System.Windows.Controls.InkCanvas.SetTop(_Ellipse, _MouseDownPoint.Y);
                if (_IsFill) _Ellipse.Fill = _Ellipse.Stroke;

                Add(_Ellipse);
            }
            else if (_Ellipse != null)
            {
                double x = (_MouseMousePoint.X + _MouseDownPoint.X) / 2;
                double y = (_MouseMousePoint.Y + _MouseDownPoint.Y) / 2;
                double r = 0;

                double w = Math.Abs(_MouseMousePoint.X - _MouseDownPoint.X);
                double h = Math.Abs(_MouseMousePoint.Y - _MouseDownPoint.Y);

                r = Math.Sqrt(w * w + h * h) / 2;

                System.Windows.Controls.InkCanvas.SetLeft(_Ellipse, x - r);
                System.Windows.Controls.InkCanvas.SetTop(_Ellipse, y - h / 2);

                _Ellipse.Width = r * 2;
                _Ellipse.Height = h;
            }
        }

        InkElement GetEllipseInkElement(System.Windows.Shapes.Ellipse ellipse)
        {
            InkElement ele = new InkElement();

            ele.ShapeType = ellipse.Width == ellipse.Height ? InkCanvasShapeType.Circle : InkCanvasShapeType.Ellipse;
            ele.StrokeColor = ((System.Windows.Media.SolidColorBrush)ellipse.Stroke).Color.ToString();
            ele.StrokeWidth = ellipse.StrokeThickness;
            ele.X = System.Windows.Controls.InkCanvas.GetLeft(ellipse);
            ele.Y = System.Windows.Controls.InkCanvas.GetTop(ellipse);
            ele.Width = ellipse.Width;
            ele.Height = ellipse.Height;
            ele.IsFill = ellipse.Fill != null;

            return ele;
        }

        void SetElllipseElement(InkElement ele, Guid userId)
        {
            var ellipse = new System.Windows.Shapes.Ellipse();
            ellipse.Stroke = new System.Windows.Media.SolidColorBrush(Utility.Common.GetColor(ele.StrokeColor));
            ellipse.StrokeThickness = ele.StrokeWidth;
            System.Windows.Controls.InkCanvas.SetLeft(ellipse, ele.X);
            System.Windows.Controls.InkCanvas.SetTop(ellipse, ele.Y);
            if (ele.IsFill) ellipse.Fill = ellipse.Stroke;
            ellipse.Width = ele.Width;
            ellipse.Height = ele.Height;

            AddChild(ellipse, userId);
        }

        private void DrawRect(bool blInit)
        {
            if (blInit)
            {
                _Rectangle = new System.Windows.Shapes.Rectangle();
                _Rectangle.Stroke = new System.Windows.Media.SolidColorBrush(_InkCanvas.DefaultDrawingAttributes.Color);
                _Rectangle.StrokeThickness = _InkCanvas.DefaultDrawingAttributes.Width;
                System.Windows.Controls.InkCanvas.SetLeft(_Rectangle, _MouseDownPoint.X);
                System.Windows.Controls.InkCanvas.SetTop(_Rectangle, _MouseDownPoint.Y);
                if (_IsFill) _Rectangle.Fill = _Rectangle.Stroke;

                Add(_Rectangle);
            }
            else if (_Rectangle != null)
            {
                double x = _MouseMousePoint.X > _MouseDownPoint.X ? _MouseDownPoint.X : _MouseMousePoint.X;
                double y = _MouseMousePoint.Y > _MouseDownPoint.Y ? _MouseDownPoint.Y : _MouseMousePoint.Y;

                System.Windows.Controls.InkCanvas.SetLeft(_Rectangle, x);
                System.Windows.Controls.InkCanvas.SetTop(_Rectangle, y);

                _Rectangle.Width = Math.Abs(_MouseMousePoint.X - _MouseDownPoint.X);
                _Rectangle.Height = Math.Abs(_MouseMousePoint.Y - _MouseDownPoint.Y);
            }
        }

        InkElement GetRectInkElement(System.Windows.Shapes.Rectangle rect)
        {
            InkElement ele = new InkElement();

            ele.ShapeType = InkCanvasShapeType.Rect;
            ele.StrokeColor = ((System.Windows.Media.SolidColorBrush)rect.Stroke).Color.ToString();
            ele.StrokeWidth = rect.StrokeThickness;
            ele.X = System.Windows.Controls.InkCanvas.GetLeft(rect);
            ele.Y = System.Windows.Controls.InkCanvas.GetTop(rect);
            ele.Width = rect.Width;
            ele.Height = rect.Height;
            ele.IsFill = rect.Fill != null;

            return ele;
        }

        void SetRectElement(InkElement ele, Guid userId)
        {
            var rectangle = new System.Windows.Shapes.Rectangle();
            rectangle.Stroke = new System.Windows.Media.SolidColorBrush(Utility.Common.GetColor(ele.StrokeColor));
            rectangle.StrokeThickness = ele.StrokeWidth;
            System.Windows.Controls.InkCanvas.SetLeft(rectangle, ele.X);
            System.Windows.Controls.InkCanvas.SetTop(rectangle, ele.Y);
            if (ele.IsFill) rectangle.Fill = rectangle.Stroke;
            rectangle.Width = ele.Width;
            rectangle.Height = ele.Height;

            AddChild(rectangle, userId);
        }

        private void DrawLine(bool blInit)
        {
            if (blInit)
            {
                _Line = new System.Windows.Shapes.Line();
                _Line.Stroke = new System.Windows.Media.SolidColorBrush(_InkCanvas.DefaultDrawingAttributes.Color);
                _Line.StrokeThickness = _InkCanvas.DefaultDrawingAttributes.Width;
                _Line.X1 = _MouseDownPoint.X;
                _Line.Y1 = _MouseDownPoint.Y;
                _Line.X2 = _MouseDownPoint.X;
                _Line.Y2 = _MouseDownPoint.Y;

                Add(_Line);
            }
            else if (_Line != null)
            {
                _Line.X2 = _MouseMousePoint.X;
                _Line.Y2 = _MouseMousePoint.Y;
            }
        }

        InkElement GetLinkInkElement(System.Windows.Shapes.Line line)
        {
            InkElement ele = new InkElement();

            ele.ShapeType = InkCanvasShapeType.Line;
            ele.StrokeColor = ((System.Windows.Media.SolidColorBrush)line.Stroke).Color.ToString();
            ele.StrokeWidth = line.StrokeThickness;
            ele.X1 = line.X1;
            ele.Y1 = line.Y1;
            ele.X2 = line.X2;
            ele.Y2 = line.Y2;

            return ele;
        }

        void SetLineElement(InkElement ele, Guid userId)
        {
            var line = new System.Windows.Shapes.Line();
            line.Stroke = new System.Windows.Media.SolidColorBrush(Utility.Common.GetColor(ele.StrokeColor));
            line.StrokeThickness = ele.StrokeWidth;
            line.X1 = ele.X1;
            line.Y1 = ele.Y1;
            line.X2 = ele.X2;
            line.Y2 = ele.Y2;

            AddChild(line, userId);
        }

        Entity.Point _MouseDownPoint { get; set; }
        Entity.Point _MouseMousePoint { get; set; }

        public void SetCursor()
        {
            if (ShapeType == InkCanvasShapeType.Ink)
            {
                _InkCanvas.Cursor = System.Windows.Input.Cursors.Pen;
            }
            else
            {
                _InkCanvas.Cursor = System.Windows.Input.Cursors.Arrow;
            }
        }

        public void SetTextFont(string fontFamily, float fontSize, bool bold, bool italic)
        {
            _TextFontFamily = fontFamily;
            _TextFontSize = fontSize;
            _TextItalic = italic;
            _TextBold = bold;
        }

        public void SetColor(string color)
        {
            if (string.IsNullOrEmpty(color)) return;
            _InkCanvas.DefaultDrawingAttributes.Color = Utility.Common.GetColor(color);
        }

        public string GetColor()
        {
            return _InkCanvas.DefaultDrawingAttributes.Color.ToString();
        }

        void _InkCanvas_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            PreviewMouseLeftButtonDown(e);
        }

        void PreviewMouseLeftButtonDown(System.Windows.Input.InputEventArgs e)
        {
            try
            {
                //if (DataDistribution.Distribution.IsReceiver && !DataDistribution.Distribution.IsSyncNote) { e.Handled = true; return; }

                _InkCanvas.Focus();

                if (ShapeType == InkCanvasShapeType.Ink) return;

                e.Handled = true;
                _IsMouseDown = true;

                _MouseDownPoint = GetMousePoint(e, _InkCanvas);

                Draw(true);
            }
            catch (Exception ex)
            {
                LoggerProxy.Exception(Name, "PreviewMouseLeftButtonDown", ex);
            }
        }

        void _InkCanvas_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            MouseMove(e);
        }

        void MouseMove(System.Windows.Input.InputEventArgs e)
        {
            try
            {
                //if (DataDistribution.Distribution.IsReceiver && !DataDistribution.Distribution.IsSyncNote) { e.Handled = true; return; }

                if (ShapeType == InkCanvasShapeType.Ink) return;

                if (_IsMouseDown)
                {
                    e.Handled = true;
                    _MouseMousePoint = GetMousePoint(e, _InkCanvas);
                    Draw(false);
                }
            }
            catch (Exception ex)
            {
                LoggerProxy.Exception(Name, "MouseMove", ex);
            }

        }

        void _InkCanvas_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
        {
            try
            {
                //if (DataDistribution.Distribution.IsReceiver) { e.Handled = true; return; }

                if (e.Key == System.Windows.Input.Key.Back && _IsBackKey) Clear();

                if ((System.Windows.Input.Keyboard.Modifiers & System.Windows.Input.ModifierKeys.Control) == System.Windows.Input.ModifierKeys.Control
                    && e.Key == System.Windows.Input.Key.Z
                    && ShapeType != InkCanvasShapeType.Text) Cancel();
            }
            catch (Exception ex)
            {
                LoggerProxy.Exception(Name, "_InkCanvas_KeyUp", ex);
            }
        }

        void _InkCanvas_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
        {
            try
            {
                if (_InkCanvas.Children.Count > 0) _InkCanvas.Children.Clear();
            }
            catch (Exception ex)
            {
                LoggerProxy.Exception(Name, "_InkCanvas_MouseEnter", ex);
            }
        }

        // protected override void SetReceiveData(object data, int actionType)
        // {
        //     switch ((DataDistribution.ActionTypes.InkCanvas)actionType)
        //     {
        //         case DataDistribution.ActionTypes.InkCanvas.Cancel: SetCancel(data); break;
        //         case DataDistribution.ActionTypes.InkCanvas.BackCancel: SetBackCancel(data); break;
        //         case DataDistribution.ActionTypes.InkCanvas.Clear: SetClear(data); break;
        //         case DataDistribution.ActionTypes.InkCanvas.Draw: SetDraw(data); break;
        //     }
        // }

        void SetBackCancel(object data)
        {
            if (data == null) return;

             Entity.InkCanvas2 entity = data as Entity.InkCanvas2;

            BackCancel(entity.UserId);
        }

        void SetCancel(object data)
        {
            if (data == null) return;

            Entity.InkCanvas2 entity = data as Entity.InkCanvas2;

            Cancel(entity.UserId);
        }

        void SetClear(object data)
        {
            if (data == null) return;

            Entity.InkCanvas2 entity = data as Entity.InkCanvas2;

            Clear(entity.UserId);
        }

        void SetDraw(object data)
        {
            if (data == null) return;

            Entity.InkCanvas entity = data as Entity.InkCanvas;

            InkElement ele = new InkElement();
            ele.Bold = entity.Bold;
            ele.FontFamily = entity.FontFamily;
            ele.FontSize = entity.FontSize;
            ele.Height = entity.Height;
            ele.IsFill = entity.IsFill;
            ele.Italic = entity.Italic;
            ele.ShapeType = (InkCanvasShapeType)entity.ShapeType;
            ele.Stroke = entity.Stroke;
            ele.StrokeColor = entity.StrokeColor;
            ele.StrokeWidth = entity.StrokeWidth;
            ele.Text = entity.Text;
            ele.Width = entity.Width;
            ele.X = entity.X;
            ele.X1 = entity.X1;
            ele.X2 = entity.X2;
            ele.Y = entity.Y;
            ele.Y1 = entity.Y1;
            ele.Y2 = entity.Y2;

            SetInkElement(ele, entity.UserId);
        }

        Entity.InkCanvas GetEntity(InkElement entity)
        {
            Entity.InkCanvas ele = new Entity.InkCanvas();

            ele.Bold = entity.Bold;
            ele.FontFamily = entity.FontFamily;
            ele.FontSize = entity.FontSize;
            ele.Height = entity.Height;
            ele.IsFill = entity.IsFill;
            ele.Italic = entity.Italic;
            ele.ShapeType = (int)entity.ShapeType;
            ele.Stroke = entity.Stroke;
            ele.StrokeColor = entity.StrokeColor;
            ele.StrokeWidth = entity.StrokeWidth;
            ele.Text = entity.Text;
            ele.Width = entity.Width;
            ele.X = entity.X;
            ele.X1 = entity.X1;
            ele.X2 = entity.X2;
            ele.Y = entity.Y;
            ele.Y1 = entity.Y1;
            ele.Y2 = entity.Y2;

            ele.Name = Name;
            ele.UserId = _UserId;

            return ele;
        }

        Entity.InkCanvas2 GetEntity2()
        {
            return new Entity.InkCanvas2()
            {
                Name = Name,
                UserId = _UserId
            };
        }

        //static DataDistribution.Actions.IAction _DataAction { get; set; }
        static List<InkCanvas> _InkCanvasList { get; set; }

        static InkCanvas()
        {
            _InkCanvasList = new List<InkCanvas>();
            //_DataAction = DataDistribution.Actions.BaseAction.GetAction("InkCanvas", (data, actionType) => BaseControl.DispatchResponse<InkCanvas>(_InkCanvasList, data, actionType));
        }
    }

    public enum InkCanvasShapeType
    {
        /// <summary>
        /// 画笔
        /// </summary>
        Ink = 0,
        /// <summary>
        /// 直线
        /// </summary>
        Line = 1,
        /// <summary>
        /// 矩形
        /// </summary>
        Rect = 2,
        /// <summary>
        /// 椭圆
        /// </summary>
        Ellipse = 3,
        /// <summary>
        /// 圆形
        /// </summary>
        Circle = 4,
        /// <summary>
        /// 文本
        /// </summary>
        Text = 5
    }

    public class InkElement
    {
        /// <summary>
        /// Ink Stroke
        /// </summary>
        public byte[] Stroke { get; set; }

        public InkCanvasShapeType ShapeType { get; set; }

        public double StrokeWidth { get; set; }
        public string StrokeColor { get; set; }
        public bool IsFill { get; set; }
        public double X { get; set; }
        public double Y { get; set; }
        public double Width { get; set; }
        public double Height { get; set; }
        public bool Italic { get; set; }
        public bool Bold { get; set; }
        public string Text { get; set; }
        public string FontFamily { get; set; }
        public double FontSize { get; set; }
        public double X1 { get; set; }
        public double Y1 { get; set; }
        public double X2 { get; set; }
        public double Y2 { get; set; }
    }
}
